package com.chensi.admin.web.oauth2;

import com.chensi.admin.web.common.Constants;
import com.chensi.admin.web.domain.SysUserToken;
import com.chensi.admin.web.util.HttpContextUtils;
import com.google.gson.Gson;
import com.chensi.admin.web.common.BaseErrorCode;
import com.chensi.admin.web.common.JsonResult;
import com.chensi.admin.web.dao.SysUserTokenRepository;
import com.chensi.admin.web.service.SysLoginService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

import static com.chensi.admin.web.common.BaseErrorCode.AUTH_ERROR;

/**
 * @Author: si.chen
 * @Date: 2019/6/20 16:19
 */
@Slf4j
public class OAuth2Filter extends AuthenticatingFilter {

    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
        //获取请求token
        String token = getRequestToken((HttpServletRequest) request);
        if (StringUtils.isBlank(token)) {
            return null;
        }
        return new OAuth2Token(token);
    }

    /**
     * 表示是否允许访问；mappedValue就是[urls]配置中拦截器参数部分，如果允许访问返回true，否则false；
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        //Subject subject = getSubject(request, response);
        //已授权的用户校验token失效，防止重复登录
        //if (subject.isAuthenticated()) {
            String token = getRequestToken((HttpServletRequest) request);
            ServletContext context = request.getServletContext();
            ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
            assert ctx != null;
            SysLoginService sysLoginService = ctx.getBean(SysLoginService.class);
            SysUserTokenRepository sysUserTokenRepository = ctx.getBean(SysUserTokenRepository.class);
            SysUserToken param = new SysUserToken();
            param.setToken(token);
            SysUserToken sysUserToken = sysLoginService.find(param);
            if (sysUserToken == null || sysUserToken.getExpireTime().getTime() < System.currentTimeMillis()) {
                return false;
            } else {
                //每次请求正确，刷新token过期时间
                Date now = new Date();
                Date expireTime = new Date(now.getTime() + Constants.TOKEN_EXPIRE * 1000);
                sysUserToken.setUpdateTime(now);
                sysUserToken.setExpireTime(expireTime);
                sysUserTokenRepository.save(sysUserToken);
                return true;
            }
        //}
        //return false;
    }

    /**
     * 表示访问拒绝时是否自己处理,如果返回true表示自己不处理且继续拦截器链执行,返回false表示自己已经处理了
     * 前置条件：isAccessAllowed返回false
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        /*String token = getRequestToken((HttpServletRequest) request);
        if (StringUtils.isBlank(token)) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setContentType("application/json;charset=utf-8");
            httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
            String json = new Gson().toJson(JsonResult.failed(AUTH_ERROR, "Token不存在"));
            httpResponse.getWriter().print(json);
            return false;
        }
        return this.executeLogin(request, response);*/
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setContentType("application/json;charset=utf-8");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
        String json = new Gson().toJson(JsonResult.failed(BaseErrorCode.TOKEN_ERROR));
        httpResponse.getWriter().print(json);
        return false;
    }

    /**
     * 登录失败处理
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setContentType("application/json;charset=utf-8");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
        try {
            //处理登录失败的异常
            Throwable throwable = e.getCause() == null ? e : e.getCause();
            String json = new Gson().toJson(JsonResult.failed(AUTH_ERROR, throwable.getMessage()));
            httpResponse.getWriter().print(json);
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        return false;
    }

    /**
     * 获取请求头的token
     */
    private String getRequestToken(HttpServletRequest httpRequest) {
        //从header中获取token
        String token = httpRequest.getHeader("token");
        //如果header中不存在token，则从参数中获取token
        if (StringUtils.isBlank(token)) {
            token = httpRequest.getParameter("token");
        }
        return token;
    }


}
